import 'dart:io';

import 'package:dio/dio.dart';
import 'package:dio/io.dart';
import 'package:flutter/cupertino.dart';

import '../utils/tools/log_util.dart';
import 'dio_token_interceptors.dart';
import 'dio_transformer.dart';
import 'pretty_dio_logger.dart';

typedef ParsingJson = T Function<T>(dynamic data);

class DioUtil {
  /// 连接超时时间
  static const connectTimeout = Duration(milliseconds: 30 * 1000);

  /// 响应超时时间
  static const receiveTimeout = Duration(milliseconds: 10 * 1000);

  static late Dio _dio;

  Dio get dio => _dio;

  factory DioUtil() => _singleton;
  static final DioUtil _singleton = DioUtil._();

  static DioUtil get instance => _singleton;

  /// 取消请求token
  CancelToken _cancelToken = CancelToken();

  DioUtil._() {
    /// 初始化基本选项
    BaseOptions options = BaseOptions(
      connectTimeout: connectTimeout,
      responseType: ResponseType.json,
      contentType: Headers.formUrlEncodedContentType,
      receiveTimeout: receiveTimeout,
    );

    /// 初始化dio
    _dio = Dio(options);

    /// 请求根地址
    _dio.options.baseUrl = 'https://aidshelp-beta.grdoc.com';

    /// 添加转换器
    _dio.transformer = DioTransformer();

    /// 刷新token拦截器(lock/unlock)
    _dio.interceptors.add(DioTokenInterceptors());

    /// 添加转换器
    _dio.transformer = DioTransformer();
    _dio.interceptors.add(
      PrettyDioLogger(
        requestHeader: true,
        requestBody: true,
        responseBody: true,
        responseHeader: false,
        error: true,
        compact: true,
        maxWidth: 120,
      ),
    );
  }

  /// 设置Http代理(设置即开启)
  void setProxy({String? proxyAddress, String? pem, bool enable = false}) {
    if (proxyAddress != null && enable) {
      dio.httpClientAdapter = IOHttpClientAdapter(
        createHttpClient: () {
          final client = HttpClient();
          client.findProxy = (uri) {
            // 将请求代理至 localhost:8888。
            // 请注意，代理会在你正在运行应用的设备上生效，而不是在宿主平台生效。
            // return 'PROXY localhost:8888';
            return proxyAddress;
          };
          if (pem != null) {
            client.badCertificateCallback = (X509Certificate cert, String host, int port) {
              return cert.pem == pem; // Verify the certificate.
            };
          }
          return client;
        },
      );
    }
  }

  /// 开启日志打印
  void openLog() {
    _dio.interceptors.add(LogInterceptor(responseBody: true));
  }

  final _methodValues = {
    DioMethod.get: 'GET',
    DioMethod.post: 'POST',
    DioMethod.put: 'PUT',
    DioMethod.delete: 'DELETE',
    DioMethod.patch: 'PATCH',
    DioMethod.head: 'HEAD',
  };

  /// 请求类
  Future<T> request<T>(
    String path, {
    DioMethod method = DioMethod.post,
    Map<String, dynamic>? params,
    Map<String, dynamic>? data,
    CancelToken? cancelToken,
    String contentType = Headers.jsonContentType,
    Options? options,
    ProgressCallback? onSendProgress,
    ProgressCallback? onReceiveProgress,
  }) async {
    if (options != null) {
      options.copyWith(method: _methodValues[method], contentType: contentType);
    } else {
      options = Options(
        method: _methodValues[method],
        contentType: contentType,
        receiveTimeout: receiveTimeout,
        sendTimeout: connectTimeout,
      );
    }
    try {
      Response response;
      response = await _dio.request(
        path,
        data: data,
        queryParameters: params,
        options: options,
        cancelToken: cancelToken ?? _cancelToken,
        onSendProgress: onSendProgress,
        onReceiveProgress: onReceiveProgress,
      );
      final json = response.data;
      print('json ===== $json');
      if (json['code'] == 200 || json['code'] == "0") {
        return json['data'];
      } else {
        return Future.error(
          DioException(
            requestOptions: response.requestOptions,
            type: DioExceptionType.badResponse,
            message: '${json['msg'] ?? '未知错误'}',
            error: response.data,
          ),
        );
      }
    } on DioException catch (e) {
      logE(('===${e.type}'));
      logE(('===${e.response}'));
      logE(('===${e.error}'));
      logE(('===${e.message}'));
      logE(('===${e.requestOptions}'));
      return Future.error(
        DioException(
          requestOptions: RequestOptions(),
          type: DioExceptionType.badResponse,
          message: '未知错误',
          error: "未知错误",
        ),
      );
      rethrow;
    }
    // Response response;
    // _dio.request(
    //   path,
    //   data: data,
    //   queryParameters: params,
    //   options: options,
    //   cancelToken: cancelToken ?? _cancelToken,
    //   onSendProgress: onSendProgress,
    //   onReceiveProgress: onReceiveProgress,
    // ).then((response) {
    //   final json = response.data;
    //   //print('json ===== $json');
    //   if (json['code'] == "200" || json['code'] == "0") {
    //     return json['data'];
    //   } else {
    //     return Future.error(
    //       DioException(
    //         requestOptions: response.requestOptions,
    //         type: DioExceptionType.badResponse,
    //         message: '${json['msg'] ?? '未知错误'}',
    //         error: response.data,
    //       ),
    //     );
    //   }
    // }).catchError((e) {
    //   logE(('===${e.type}'));
    //   logE(('===${e.response}'));
    //   logE(('===${e.error}'));
    //   logE(('===${e.message}'));
    //   logE(('===${e.requestOptions}'));
    //   return Future.error(
    //     DioException(
    //       requestOptions: RequestOptions(),
    //       type: DioExceptionType.badResponse,
    //       message: '未知错误',
    //       error: "未知错误",
    //     ),
    //   );
    // });
  }

  /// 请求类
  Future<T> upload<T>(
    String path, {
    UrlType urlType = UrlType.sport,
    Object? data,
    ProgressCallback? onSendProgress,
  }) async {
    try {
      Response response;
      response = await _dio.post(
        path,
        data: data,
        options: Options(headers: {'Content-Type': 'multipart/form-data'}),
        onSendProgress: onSendProgress,
      );
      final json = response.data;
      if (json['code'] == 200 || json['code'] == 0) {
        return json['data'];
      } else {
        return Future.error(
          DioException(
            requestOptions: response.requestOptions,
            type: DioExceptionType.badResponse,
            message: '${json['msg'] ?? '未知错误'}',
            error: response.data,
          ),
        );
      }
    } on DioException catch (e) {
      logE(('===${e.type}'));
      logE(('===${e.response}'));
      logE(('===${e.error}'));
      logE(('===${e.message}'));
      logE(('===${e.requestOptions}'));
      debugPrintStack(stackTrace: e.stackTrace, label: 'lp');
      rethrow;
    }
  }

  /// 取消网络请求
  void cancelRequests({CancelToken? token}) {
    token ?? _cancelToken.cancel("cancelled");
    _cancelToken = CancelToken();
  }
}

/// 请求方式类型
enum DioMethod { get, post, put, delete, patch, head }

/// 请求地址类型
enum UrlType { server, sport }
